package com.br.serial.rs232;

import gnu.io.CommPortIdentifier;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.List;
import java.util.Vector;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;

import com.br.serial.rs232.service.ConexaoService;
import com.br.serial.rs232.service.IConexaoEventosListener;

public class RS232 extends JFrame implements IConexaoEventosListener {
	private static final long serialVersionUID = 1L;

	private static final String APP_TITLE = "RS-232";
	private static final String LBL_PORTA = "Porta";
	private static final String LBL_VELOCIDADE = "Velocidade";
	private static final String BTN_ATUALIZAR = "Atualizar";
	private static final String BTN_TEXT_CONECTAR = "Conectar";
	private static final String BTN_TEXT_DESCONECTAR = "Desconectar";
	private static final String BTN_TEXT_SAIR = "Sair";
	private static final String LBL_RX = "RX";
	private static final String LBL_TX = "TX";
	private static final String CB_CR = "CR";
	private static final String CB_LF = "LF";
	private static final String BTN_ENVIAR = "Enviar";
	private static final String BTN_LIMPAR = "Limpar";
	private static final String TITLED_BORDER_BORDER = "TitledBorder.border";

	private ConexaoService conexaoService = new ConexaoService(this);

	private JPanel contentPane;

	private JList<String> jListRX;
	private JTextArea jTextAreaTX;
	private JCheckBox chckbxLf;
	private JCheckBox chckbxCr;
	private JButton btnEnviar;

	private JComboBox<CommPortIdentifier> cmbPorta;
	private JButton btnAtualizarPortas;
	private JComboBox<Integer> cmbVelocidade;
	private JButton btnConectar;
	private JButton btnDesconectar;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					UIManager.setLookAndFeel(NimbusLookAndFeel.class.getName());
					RS232 frame = new RS232();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public RS232() {
		iniciarFrame();

		adicionarPanelPrincipal();

		adicionarPanelConexao();

		adicionarPanelTxRx();

		configComponentDesconectado();
	}

	private void iniciarFrame() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 600, 400);
		setTitle(APP_TITLE);
		setResizable(true);
	}

	private void adicionarPanelPrincipal() {
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
	}

	private void adicionarPanelConexao() {
		JPanel panelConexao = new JPanel();
		panelConexao.setBorder(UIManager.getBorder(TITLED_BORDER_BORDER));
		contentPane.add(panelConexao, BorderLayout.EAST);

		JLabel lblPorta = new JLabel(LBL_PORTA);
		cmbPorta = new JComboBox<CommPortIdentifier>(new Vector<CommPortIdentifier>(ConexaoService.buscarListaDePortasCom()));
		cmbPorta.setRenderer(new NomeDaPortaRenderer());

		btnAtualizarPortas = new JButton(BTN_ATUALIZAR);
		btnAtualizarPortas.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				updatePorts(ConexaoService.buscarListaDePortasCom());
			}
		});

		JLabel lblVelocidade = new JLabel(LBL_VELOCIDADE);
		cmbVelocidade = new JComboBox<Integer>(new Vector<Integer>(ConexaoService.getBaudList()));
		cmbVelocidade.setSelectedItem(new Integer(9600));

		btnConectar = new JButton(BTN_TEXT_CONECTAR);
		btnConectar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				CommPortIdentifier portaSelecionada = (CommPortIdentifier) cmbPorta.getModel().getSelectedItem();
				Integer velocidadeSelecionada = (Integer) cmbVelocidade.getModel().getSelectedItem();

				conexaoService.conectar(portaSelecionada, velocidadeSelecionada);
			}
		});

		btnDesconectar = new JButton(BTN_TEXT_DESCONECTAR);
		btnDesconectar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				conexaoService.desconectar();
			}
		});

		JButton btnSair = new JButton(BTN_TEXT_SAIR);
		btnSair.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});

		GroupLayout gl_panelConexao = new GroupLayout(panelConexao);
		gl_panelConexao.setHorizontalGroup(
			gl_panelConexao.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panelConexao.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_panelConexao.createParallelGroup(Alignment.LEADING)
						.addComponent(btnAtualizarPortas, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
						.addComponent(lblPorta, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
						.addComponent(cmbPorta, Alignment.TRAILING, 0, 107, Short.MAX_VALUE)
						.addComponent(lblVelocidade, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
						.addComponent(cmbVelocidade, Alignment.TRAILING, 0, 107, Short.MAX_VALUE)
						.addComponent(btnConectar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
						.addComponent(btnDesconectar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
						.addComponent(btnSair, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE))
					.addContainerGap())
		);
		gl_panelConexao.setVerticalGroup(
			gl_panelConexao.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panelConexao.createSequentialGroup()
					.addContainerGap()
					.addComponent(lblPorta, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(cmbPorta, GroupLayout.PREFERRED_SIZE, 26, GroupLayout.PREFERRED_SIZE)
					.addGap(1)
					.addComponent(btnAtualizarPortas, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(lblVelocidade, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(cmbVelocidade, GroupLayout.PREFERRED_SIZE, 26, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED, 100, Short.MAX_VALUE)
					.addComponent(btnConectar, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(btnDesconectar, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(btnSair, GroupLayout.PREFERRED_SIZE, 28, GroupLayout.PREFERRED_SIZE)
					.addContainerGap())
		);
		panelConexao.setLayout(gl_panelConexao);
	}

	private void adicionarPanelTxRx() {
		JPanel txRxPanel = new JPanel();
		txRxPanel.setBorder(UIManager.getBorder(TITLED_BORDER_BORDER));
		contentPane.add(txRxPanel, BorderLayout.CENTER);

		JButton btnLimpar = new JButton(BTN_LIMPAR);
		btnLimpar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				limpaJListRX();
			}
		});

		JLabel lblRx = new JLabel(LBL_RX);
		JScrollPane scrollPaneRX = new JScrollPane();
		jListRX = new JList<String>();
		scrollPaneRX.setViewportView(jListRX);
		jListRX.setModel(new DefaultListModel<String>());

		JLabel lblTX = new JLabel(LBL_TX);
		JScrollPane scrollPaneTX = new JScrollPane();
		jTextAreaTX = new JTextArea();
		scrollPaneTX.setViewportView(jTextAreaTX);

		chckbxLf = new JCheckBox(CB_LF, true);
		chckbxLf.addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent e) {
				conexaoService.setHasLf(((JCheckBox) e.getItemSelectable()).isSelected());
			}
		});
		chckbxCr = new JCheckBox(CB_CR, true);
		chckbxCr.addItemListener(new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent e) {
				conexaoService.setHasCr(((JCheckBox) e.getItemSelectable()).isSelected());
			}
		});

		btnEnviar = new JButton(BTN_ENVIAR);
		btnEnviar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				conexaoService.enviarMsg(jTextAreaTX.getText());
				limpaJTextAreaTX();
			}
		});

		GroupLayout gl_txRxPanel = new GroupLayout(txRxPanel);
		gl_txRxPanel.setHorizontalGroup(
			gl_txRxPanel.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_txRxPanel.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_txRxPanel.createParallelGroup(Alignment.LEADING)
						.addGroup(gl_txRxPanel.createSequentialGroup()
							.addGroup(gl_txRxPanel.createParallelGroup(Alignment.LEADING)
								.addComponent(chckbxLf, GroupLayout.PREFERRED_SIZE, 40, GroupLayout.PREFERRED_SIZE)
								.addComponent(chckbxCr))
							.addPreferredGap(ComponentPlacement.RELATED, 307, Short.MAX_VALUE)
							.addComponent(btnEnviar))
						.addComponent(scrollPaneTX, GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE)
						.addComponent(scrollPaneRX, GroupLayout.DEFAULT_SIZE, 409, Short.MAX_VALUE)
						.addGroup(gl_txRxPanel.createSequentialGroup()
							.addComponent(lblRx, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.RELATED, 317, Short.MAX_VALUE)
							.addComponent(btnLimpar))
						.addGroup(gl_txRxPanel.createSequentialGroup()
							.addComponent(lblTX, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.RELATED, 384, Short.MAX_VALUE)))
					.addContainerGap())
		);
		gl_txRxPanel.setVerticalGroup(
			gl_txRxPanel.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_txRxPanel.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_txRxPanel.createParallelGroup(Alignment.TRAILING)
						.addComponent(lblRx, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE)
						.addComponent(btnLimpar, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(scrollPaneRX, GroupLayout.DEFAULT_SIZE, 139, Short.MAX_VALUE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(lblTX, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(scrollPaneTX, GroupLayout.PREFERRED_SIZE, 82, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addGroup(gl_txRxPanel.createParallelGroup(Alignment.TRAILING)
						.addGroup(gl_txRxPanel.createSequentialGroup()
							.addGroup(gl_txRxPanel.createParallelGroup(Alignment.LEADING)
								.addComponent(btnEnviar)
								.addComponent(chckbxLf))
							.addGap(10))
						.addGroup(gl_txRxPanel.createSequentialGroup()
							.addComponent(chckbxCr)
							.addGap(1))))
		);
		txRxPanel.setLayout(gl_txRxPanel);
	}

	private class NomeDaPortaRenderer extends DefaultListCellRenderer {
		private static final long serialVersionUID = 1L;

		@Override
		public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
			String nomePorta = null;
			if (value != null) {
				nomePorta = ((CommPortIdentifier) value).getName();
			}
			return super.getListCellRendererComponent(list, nomePorta, index, isSelected, cellHasFocus);
		}
	}

	@Override
	public void receberMsg(String msg) {
		((DefaultListModel<String>) jListRX.getModel()).addElement(msg);
		jListRX.setSelectedIndex(jListRX.getModel().getSize() - 1);
		jListRX.ensureIndexIsVisible(jListRX.getModel().getSize() - 1);
	}

	@Override
	public void conectado() {
		configComponentConectado();
	}

	@Override
	public void desconectado() {
		configComponentDesconectado();
	}

	@Override
	public void error(String msg) {
		System.out.println(msg);
	}

	@Override
	public void updatePorts(List<CommPortIdentifier> listaDePortasCom) {
		CommPortIdentifier selectedItem = (CommPortIdentifier) cmbPorta.getModel().getSelectedItem();
		cmbPorta.removeAllItems();

		for (CommPortIdentifier commPortIdentifier : listaDePortasCom) {
			cmbPorta.addItem(commPortIdentifier);

			if (selectedItem.getName().equals(commPortIdentifier.getName())) {
				cmbPorta.getModel().setSelectedItem(commPortIdentifier);
			}
		}
	}

	public void configComponentConectado() {
		jTextAreaTX.setEnabled(true);
		chckbxLf.setEnabled(true);
		chckbxCr.setEnabled(true);
		btnEnviar.setEnabled(true);
		btnDesconectar.setEnabled(true);
		cmbPorta.setEnabled(false);
		btnAtualizarPortas.setEnabled(false);
		cmbVelocidade.setEnabled(false);
		btnConectar.setEnabled(false);
	}

	public void configComponentDesconectado() {
		limpaJTextAreaTX();
		jTextAreaTX.setEnabled(false);
		chckbxLf.setEnabled(false);
		chckbxCr.setEnabled(false);
		btnEnviar.setEnabled(false);
		btnDesconectar.setEnabled(false);
		cmbPorta.setEnabled(true);
		btnAtualizarPortas.setEnabled(true);
		cmbVelocidade.setEnabled(true);
		btnConectar.setEnabled(true);
	}

	public void limpaJTextAreaTX() {
		jTextAreaTX.setText("");
	}

	public void limpaJListRX() {
		((DefaultListModel<String>) jListRX.getModel()).clear();
	}
}
